home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZMemUtils.cpp < prev    next >
Text File  |  1997-06-18  |  16KB  |  681 lines

  1. /*
  2.  *  File:       ZMemUtils.cpp
  3.  *  Summary:       Misc memory utilities.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <3>     4/13/97    JDJ        Includes Gestalt.h
  12.  *         <2>     4/13/97    JDJ        TemporaryZone no longer caches zone.
  13.  *         <1>     1/14/96    JDJ        Created.
  14.  */
  15.  
  16. #include <ZMemUtils.h>
  17.  
  18. #include <Errors.h>
  19. #include <Gestalt.h>
  20. #include <Resources.h>
  21.  
  22. #include <ZDebug.h>
  23. #include <ZExceptions.h>
  24. #include <ZUnitTest.h>
  25.  
  26.  
  27. // ===================================================================================
  28. //    Helper Functions
  29. // ===================================================================================
  30.  
  31. //---------------------------------------------------------------
  32. //
  33. // LowestPossibleAddress
  34. //
  35. //---------------------------------------------------------------
  36. static void* LowestPossibleAddress()
  37. {
  38.     static void* address = &SystemZone()->heapData;
  39.     
  40.     return address;
  41. }
  42.  
  43.  
  44. //---------------------------------------------------------------
  45. //
  46. // HighestPossibleAddress
  47. //
  48. //---------------------------------------------------------------
  49. static void* HighestPossibleAddress()
  50. {
  51.     static void* address = nil;
  52.     
  53.     if (address == nil) {
  54.         long logicalRAM;
  55.         if (Gestalt(gestaltLogicalRAMSize, &logicalRAM) != noErr)
  56.             logicalRAM = 128*1024L*1024L;
  57.  
  58.         address = (void*) logicalRAM;
  59.     }
  60.     
  61.     return address;
  62. }
  63.  
  64. #pragma mark -
  65.  
  66. // ===================================================================================
  67. //    Allocation
  68. // ===================================================================================
  69.  
  70. //---------------------------------------------------------------
  71. //
  72. // CreatePtr
  73. //
  74. //---------------------------------------------------------------
  75. void* CreatePtr(ulong bytes, bool zeroBytes)
  76. {
  77.     void* ptr = nil;
  78.     
  79.     ptr = NewPtr(bytes);
  80.  
  81.     if (ptr != nil) {
  82.         if (zeroBytes)
  83.             SetMemory(ptr, 0, bytes);    
  84. #if DEBUG
  85.         else    
  86.             SetMemory(ptr, kNewFill, bytes);    
  87. #endif        
  88.     }
  89.  
  90.     return ptr;
  91. }
  92.  
  93.  
  94. //---------------------------------------------------------------
  95. //
  96. // DisposeIfPtr
  97. //
  98. //---------------------------------------------------------------
  99. void DisposeIfPtr(void* ptr)
  100. {
  101.     if (ptr != nil) {
  102.         ValidatePtr(ptr);
  103.  
  104. #if DEBUG
  105.         long size = GetPtrSize((Ptr) ptr);
  106.         SetMemory(ptr, kFreeFill, (ulong) size);
  107. #endif
  108.  
  109.         DisposePtr((Ptr) ptr);
  110.     }
  111. }
  112.  
  113.  
  114. //---------------------------------------------------------------
  115. //
  116. // ValidatePtr
  117. //
  118. //---------------------------------------------------------------
  119. #if DEBUG
  120. void ValidatePtr(void* ptr)
  121. {
  122.     if (ptr == nil)                                
  123.         DEBUGSTR("Ptr is nil.");
  124.                                     
  125.     else if (((long) ptr & 0x3) != 0)                             
  126.         DEBUGSTR("Ptr is not on a long-word boundary (%lX).", (long) ptr);
  127.                 
  128.     else if (ptr < LowestPossibleAddress())
  129.         DEBUGSTR("Ptr is too small (%lX).", (long) ptr);
  130.  
  131.     else if (ptr > HighestPossibleAddress())
  132.         DEBUGSTR("Ptr is too large (%lX).", (long) ptr);
  133. }
  134. #endif
  135.  
  136.  
  137. //---------------------------------------------------------------
  138. //
  139. // CreateHandle
  140. //
  141. //---------------------------------------------------------------
  142. Handle CreateHandle(ulong bytes, int options)
  143. {
  144.     Handle hand = nil;
  145.  
  146.     ASSERT(bytes < 16*1024L*1024L);
  147.     ASSERT((options & ~(kZeroBytes | kUseTempHeap | kUseAppHeap)) == 0);
  148.  
  149.     bool zeroBytes = (options & kZeroBytes)   == kZeroBytes;
  150.     bool tempMem   = (options & kUseTempHeap) == kUseTempHeap;
  151.     bool appHeap   = (options & kUseAppHeap)  == kUseAppHeap;
  152.     
  153.     if (tempMem) {
  154.         OSErr err;
  155.         hand = TempNewHandle((long) bytes, &err);
  156.     }
  157.     else
  158.         hand = NewHandle(bytes);
  159.  
  160.     if (hand != nil) {
  161.         ValidateHandle(hand);
  162.  
  163.         if (zeroBytes)
  164.             SetMemory(*hand, 0, bytes);    
  165. #if DEBUG
  166.         else    
  167.             SetMemory(*hand, kNewFill, bytes);    
  168. #endif        
  169.     }
  170.  
  171.     return hand;
  172. }
  173.  
  174.  
  175. //---------------------------------------------------------------
  176. //
  177. // DisposeIfHandle
  178. //
  179. //---------------------------------------------------------------
  180. void DisposeIfHandle(Handle hand)
  181. {
  182.     if (hand != nil) {
  183.         ASSERT(hand != GZSaveHnd());            // ensure we're not messing with the growzoneユs protected handle
  184.         ASSERT(!IsResource(hand));
  185.         
  186.         if (*hand != nil) {
  187.             ValidateHandle(hand);
  188.  
  189. #if DEBUG
  190.             ulong size = (ulong) GetHandleSize(hand);
  191.             SetMemory(*hand, kFreeFill, size);
  192. #endif
  193.             
  194.         } else
  195.             ASSERT(IsPurgeable(hand));
  196.             
  197.         ::DisposeHandle(hand);
  198.     }
  199. }
  200.  
  201.  
  202. //---------------------------------------------------------------
  203. //
  204. // ValidateHandle
  205. //
  206. //---------------------------------------------------------------
  207. #if DEBUG
  208. void ValidateHandle(Handle hand)
  209. {
  210.     if (hand == nil)                                
  211.         DEBUGSTR("Handle is nil.");
  212.                                     
  213.     else if (((long) hand & 0x3) != 0)
  214.         DEBUGSTR("Handle is not on a long-word boundary (%lX).", (long) hand);
  215.  
  216.     else if (hand < LowestPossibleAddress())
  217.         DEBUGSTR("Handle is too small (%lX).", (long) hand);
  218.  
  219.     else if (hand > HighestPossibleAddress())
  220.         DEBUGSTR("Handle is too large (%lX).", (long) hand);
  221.         
  222.     else if (*hand == nil)
  223.         /* can be purged */;
  224.  
  225.     else if (((long) *hand & 0x3) != 0)                             
  226.         DEBUGSTR("Master pointer is not on a long-word boundary (%lX).", (long) *hand);
  227.         
  228.     else if (*hand < LowestPossibleAddress())
  229.         DEBUGSTR("Master pointer is too small (%lX).", (long) *hand);
  230.  
  231.     else if (*hand > HighestPossibleAddress())
  232.         DEBUGSTR("Master pointer is too large (%lX).", (long) *hand);
  233.  
  234. #if 0                                                        // Spotlight doesn't like this code
  235.     else {
  236.         THz zone = HandleZone(hand);
  237.         OSErr err = MemError();
  238.  
  239.         if (err == noErr) {
  240.             if (zone == ApplicationZone()) {                // Temp memory doesn't appear to be a real zone...
  241.                 void* heapStart = &zone->heapData;
  242.                 void* heapEnd   = zone->bkLim;
  243.         
  244.                 if (hand < heapStart || hand >= heapEnd)
  245.                     DEBUGSTR("Handle is outside of heap.");
  246.                 else if (*hand < heapStart || *hand >= heapEnd)
  247.                     DEBUGSTR("Master pointer is outside of heap.");
  248.             }
  249.         } else
  250.             DEBUGSTR("Error %d calling HandleZone.", err);
  251.     }
  252. #endif
  253. }
  254. #endif
  255.  
  256. #pragma mark -
  257.  
  258. // ===================================================================================
  259. //    Handle State
  260. // ===================================================================================
  261.  
  262. //---------------------------------------------------------------
  263. //
  264. // IsLocked
  265. //
  266. //---------------------------------------------------------------
  267. bool IsLocked(Handle hand)
  268. {
  269.     ValidateHandle(hand);
  270.     
  271.     char state = HGetState(hand);
  272.     ASSERT(MemError() == noErr);
  273.     return (state & 0x80) != 0;
  274. }
  275.  
  276.  
  277. //---------------------------------------------------------------
  278. //
  279. // IsPurgeable
  280. //
  281. //---------------------------------------------------------------
  282. bool IsPurgeable(Handle hand)
  283. {
  284.     ASSERT(hand != nil);
  285.     
  286.     char state = HGetState(hand);
  287.     OSErr err = MemError();
  288.     
  289.     if (err == noErr)
  290.         return (state & 0x40) != 0;
  291.     else if (err == nilHandleErr)
  292.         return true;                                // Handle has been purged.
  293.     else
  294.         DEBUGSTR("Error %d in IsPurgeable.", err);
  295.         
  296.     return false;
  297. }
  298.  
  299.  
  300. //---------------------------------------------------------------
  301. //
  302. // IsResource
  303. //
  304. //---------------------------------------------------------------
  305. bool IsResource(Handle hand)
  306. {
  307.     ValidateHandle(hand);                // Might want to treat this like IsPurgeable.
  308.  
  309.     char state = HGetState(hand);
  310.     ASSERT(MemError() == noErr);
  311.     return (state & 0x20) != 0;
  312. }
  313.  
  314. #pragma mark -
  315.  
  316. // ===================================================================================
  317. //    Operations
  318. // ===================================================================================
  319.  
  320. //---------------------------------------------------------------
  321. //
  322. // ClearMemory
  323. //
  324. //---------------------------------------------------------------
  325. void ClearMemory(void* adr, ulong byteCount)
  326. {
  327.     Byte* destPtr = (Byte *) adr;
  328.     Byte* endPtr = nil;
  329.     unsigned long longSetVal = 0;
  330.     long* longEndPtr = nil;
  331.     long* longSetValPtr;
  332.  
  333.     endPtr = (Byte *) (destPtr + byteCount);
  334.  
  335.     longEndPtr = (long *) ((long) (destPtr + byteCount) & 0xFFFFFFFC);// Trunc to nearest 4 bytes
  336.  
  337.     // We do longword assignments when we have a chance
  338.     if (byteCount >= 4) {
  339.         while (((long) destPtr) & 0x00000003)            // Starting on an odd byte boundry
  340.             *destPtr++ = 0;
  341.  
  342.         // Assign in 4 byte chunks what we can
  343.         for (longSetValPtr = (long *) destPtr; longSetValPtr < longEndPtr;)
  344.             *longSetValPtr++ = 0;
  345.         destPtr = (Byte *) longSetValPtr;
  346.     }
  347.  
  348.     // Now finish assigning odd bytes
  349.     while (destPtr < endPtr)
  350.         *destPtr++ = 0;
  351.  
  352.  
  353. //---------------------------------------------------------------
  354. //
  355. // SetMemory
  356. //
  357. //    Much thanks for this improved version to Scott D. Schmitz (from MacApp)
  358. //
  359. //---------------------------------------------------------------
  360. void SetMemory(void* destPtr, Byte setVal, ulong byteCount)
  361. {
  362.     // here are the results of using chars (1), longs (4) or doubles (8) on 68K and PowerPC
  363.     //                 68K                601
  364.     //---------------------------------------
  365.     // char            261    (100)        237 (100)
  366.     // long            156    (60)        68     (29)
  367.     // double        933    (357)        46    (19)
  368.     //---------------------------------------
  369.     // the poor result for 68K/double is to be expected. Jeroen Schalk, DTS.
  370.  
  371. #if powerc
  372.     const unsigned long    kBytesPerPunch = 8;
  373.     typedef double        Punch, *PunchPtr;        // select type double for best performance
  374. #else
  375.     const unsigned long        kBytesPerPunch = 4;
  376.     typedef unsigned long    Punch, *PunchPtr;    // select type long for best performance
  377. #endif
  378.  
  379.     Byte *begPtr    = (Byte *) StripAddress(destPtr);
  380.     Byte *endPtr    = (Byte *) (begPtr + byteCount);
  381.  
  382.     // this looks like the right cutoff, since for the optimization 
  383.     // O(n) = kBPP + kBPP/2 + n/kBPP + kBPP/2 = 2*kBPP + n/kBPP
  384.     // a simple linear fill has O(n) = n
  385.     // n > 2*kBPP + n/kBPP if n > 2*kBPP, since 1/kBPP ナ 0.
  386.  
  387.     if (byteCount >= (4 * kBytesPerPunch)) {
  388.         // progress to nearest 4 byte boundary. O(n) = kBytesPerPunch/2
  389.         while ((long) begPtr & (kBytesPerPunch - 1))
  390.             *begPtr++ = setVal;
  391.  
  392.         // lets get a kBytesPerPunch byte 'punch'. O(n) = kBytesPerPunch
  393.         register PunchPtr punchSetValPtr = (PunchPtr)begPtr;    // save pointer to the first value
  394. #if powerc
  395.         *begPtr++ = setVal;                                        // fill it in
  396.         *begPtr++ = setVal;
  397.         *begPtr++ = setVal;
  398.         *begPtr++ = setVal;
  399. #endif
  400.         *begPtr++ = setVal;
  401.         *begPtr++ = setVal;
  402.         *begPtr++ = setVal;
  403.         *begPtr++ = setVal;
  404.         register Punch punchSetVal = *punchSetValPtr++;            // pick it up
  405.  
  406.         // truncate to nearest kBytesPerPunch bytes
  407.         PunchPtr punchEndPtr = (PunchPtr)((long) endPtr & (0xFFFFFFFF - (kBytesPerPunch - 1)));
  408.  
  409.         // assign in kBytesPerPunch byte chunks what we can. O(n) = n/kBytesPerPunch
  410.         while (punchSetValPtr < punchEndPtr)
  411.             *punchSetValPtr++ = punchSetVal;
  412.  
  413.         begPtr = (Byte *) punchSetValPtr;
  414.         }
  415.  
  416.     // now finish assigning odd bytes. O(n) = kBytesPerPunch/2 if optimization chosen.
  417.     while (begPtr < endPtr)
  418.         *begPtr++ = setVal;
  419.  
  420. }
  421.  
  422.  
  423. //---------------------------------------------------------------
  424. //
  425. // InvertMemory
  426. //
  427. //---------------------------------------------------------------
  428. void InvertMemory(void* adr, ulong byteCount)
  429. {
  430.     ASSERT(adr != nil);
  431.     ASSERT(byteCount > 0);
  432.  
  433.     Byte* ptr = (Byte *) adr;
  434.  
  435.     if (((ulong) ptr & 0x1) || (byteCount & 0x3)) {
  436.         TRACEFLOW("ZWarning", "InvertBlock(): warning - using slow method (odd pointer or byte count not % 4)¥n");
  437.  
  438.         Byte* bytes = (Byte *) ptr;
  439.  
  440.         while (byteCount--)
  441.             *bytes++ ^= (Byte) (~0x0);
  442.  
  443.     } else {
  444.         ulong* longs = (ulong *) ptr;
  445.         ulong longCount = byteCount >> 2;
  446.  
  447.         while (longCount--)
  448.             *longs++ ^= ~0x0;
  449.     }
  450. }
  451.  
  452. #pragma mark -
  453.  
  454. // ===================================================================================
  455. //    Bit twiddling
  456. // ===================================================================================
  457.  
  458. //---------------------------------------------------------------
  459. //
  460. // TestBit
  461. //
  462. //---------------------------------------------------------------
  463. bool TestBit(const void* bytePtr, ushort bit)
  464. {
  465.     ushort    index = (ushort) (bit >> 3);
  466.     ushort    mask = (ushort) (1 << ((bit & 0x07) ^ 0x07));
  467.  
  468.     return (((Byte *) bytePtr)[index] & mask) != 0;
  469. }
  470.  
  471.  
  472. //---------------------------------------------------------------
  473. //
  474. // SetBit
  475. //
  476. //---------------------------------------------------------------
  477. void SetBit(void* bytePtr, ushort bit)
  478. {
  479.     ushort    index = (ushort) (bit >> 3);
  480.     Byte    mask = (Byte) (1 << ((bit & 0x07) ^ 0x07));
  481.  
  482.     ((Byte *) bytePtr)[index] |= mask;
  483. }
  484.  
  485.  
  486. //---------------------------------------------------------------
  487. //
  488. // ClearBit
  489. //
  490. //---------------------------------------------------------------
  491. void ClearBit(void* bytePtr, ushort bit)
  492. {
  493.     ushort    index = (ushort) (bit >> 3);
  494.     ushort    mask = (Byte) (1 << ((bit & 0x07) ^ 0x07));
  495.  
  496.     ((Byte *) bytePtr)[index] &= (Byte) (~mask);
  497. }
  498.  
  499.  
  500. //---------------------------------------------------------------
  501. //
  502. // InvertBit
  503. //
  504. //---------------------------------------------------------------
  505. void InvertBit(void* bytePtr, ushort bit)
  506. {
  507.     ushort    index = (ushort) (bit >> 3);
  508.     Byte    mask = (Byte) (1 << ((bit & 0x07) ^ 0x07));
  509.  
  510.     ((Byte *) bytePtr)[index] ^= mask;
  511. }
  512.  
  513. #pragma mark -
  514.  
  515. // ===================================================================================
  516. //    Heaps
  517. // ===================================================================================
  518.  
  519. //---------------------------------------------------------------
  520. //
  521. // TemporaryZone
  522. //
  523. //---------------------------------------------------------------
  524. THz TemporaryZone()
  525. {
  526.     OSErr err;
  527.     Handle h = TempNewHandle(1, &err);
  528.     ThrowIfMemFail(h);
  529.         
  530.     THz zone = HandleZone(h);        // MMSystemFreeSpace (in MacApp) sez this can't be cached
  531.     
  532.     DisposeHandle(h);
  533.     
  534.     return zone;
  535. }
  536.  
  537.  
  538. //---------------------------------------------------------------
  539. //
  540. // WalkHeap
  541. //
  542. //---------------------------------------------------------------
  543. #if DEBUG
  544. void WalkHeap(THz zone, HeapWalkerProc callback, void* refCon)
  545. {
  546.     ASSERT(zone != nil);
  547.     ASSERT(zone != TemporaryZone());            // temporary zone header is completely different than all the others...
  548.     ASSERT(callback != nil);
  549.     ASSERT((zone->heapType & kNewStyleHeap) != 0);
  550.                 
  551.     SHeapBlock* blockStart = reinterpret_cast<SHeapBlock*>((Byte*) zone + kZoneHeaderSize);
  552.     ASSERT(blockStart != nil);
  553.  
  554.     SHeapBlock* block = reinterpret_cast<SHeapBlock*>((Byte*) zone + 64)->next;
  555.     ASSERT(block != nil);
  556.     
  557.     while (block >= blockStart) {                // last block points into zone header
  558.         (*callback)(block, refCon);
  559.                 
  560.         block = block->next;    
  561.         ASSERT(block != nil);
  562.     }
  563. }
  564. #endif
  565.  
  566. #pragma mark -
  567.  
  568. // ===================================================================================
  569. //    Unit Test
  570. // ===================================================================================
  571.  
  572. //---------------------------------------------------------------
  573. //
  574. // VerifyBlock
  575. //
  576. //---------------------------------------------------------------
  577. #if DEBUG
  578. static void VerifyBlock(Byte* block, ulong size, Byte value)
  579. {
  580.     Byte* ptr = block;
  581.     for (long i = 0; i < size; i++)
  582.         ASSERT(*ptr++ == value);
  583. }
  584. #endif    // DEBUG
  585.  
  586.  
  587. //---------------------------------------------------------------
  588. //
  589. // TestMemUtils
  590. //
  591. //---------------------------------------------------------------
  592. #if DEBUG
  593. static void TestMemUtils()
  594. {
  595.     Byte block1[100];
  596.     Byte block2[205];
  597.     
  598.     ClearMemory(block1, 100);
  599.     VerifyBlock(block1, 100, 0);
  600.     
  601.     SetMemory(block2, 205, 34);
  602.     VerifyBlock(block2, 34, 205);
  603.     
  604.     InvertMemory(block1, 100);
  605.     VerifyBlock(block1, 100, 0xFF);
  606.     
  607.     ASSERT(!EqualMemory(block1, block2, 100));
  608.     
  609.  
  610.     Handle h = CreateHandle(100, kUseAppHeap + kZeroBytes);
  611.     VerifyBlock((Byte*) *h, 100, 0);
  612.     
  613.     ASSERT(!IsLocked(h));
  614.     ASSERT(!IsPurgeable(h));
  615.     ASSERT(!IsResource(h));
  616.     
  617.     HLock(h);
  618.     ASSERT(IsLocked(h));
  619.     ASSERT(!IsPurgeable(h));
  620.     ASSERT(!IsResource(h));
  621.     
  622.     HPurge(h);
  623.     ASSERT(IsLocked(h));
  624.     ASSERT(IsPurgeable(h));
  625.     ASSERT(!IsResource(h));
  626.     
  627.     DisposeIfHandle(h);
  628.     
  629.     
  630.     h = CreateHandle(100, kUseTempHeap);
  631.     VerifyBlock((Byte*) *h, 100, kNewFill);
  632.     
  633.     ASSERT(!IsLocked(h));
  634.     ASSERT(!IsPurgeable(h));
  635.     ASSERT(!IsResource(h));
  636.     
  637.     HLock(h);
  638.     ASSERT(IsLocked(h));
  639.     ASSERT(!IsPurgeable(h));
  640.     ASSERT(!IsResource(h));
  641.  
  642.     HPurge(h);
  643.     ASSERT(IsLocked(h));
  644.     ASSERT(IsPurgeable(h));
  645.     ASSERT(!IsResource(h));
  646.     
  647.     DisposeIfHandle(h);
  648.     
  649.     
  650.     h = GetResource('SIZE', -1);
  651.     
  652.     ASSERT(!IsLocked(h));
  653.     ASSERT(!IsPurgeable(h));
  654.     ASSERT(IsResource(h));
  655.     
  656.     HLock(h);
  657.     ASSERT(IsLocked(h));
  658.     ASSERT(!IsPurgeable(h));
  659.     ASSERT(IsResource(h));
  660.     
  661.     DetachResource(h);
  662.     ASSERT(IsLocked(h));
  663.     ASSERT(!IsPurgeable(h));
  664.     ASSERT(!IsResource(h));
  665.  
  666.     HPurge(h);
  667.     ASSERT(IsLocked(h));
  668.     ASSERT(IsPurgeable(h));
  669.     ASSERT(!IsResource(h));
  670.     
  671.     DisposeIfHandle(h);
  672.     
  673.         
  674.     TRACE("Completed memory utils test.¥n¥n");
  675. }
  676.  
  677. static TUnitTestRegistrar sMemReg("Memory Utils", TestMemUtils);
  678.  
  679. #endif    // DEBUG
  680.